package tool;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

public class MatchesFinder {
	private static final String InputFile = "MarkedTrainingData.txt";
	private static final String OutputFile = "RegexSearchResult.xml";
	private static final String RegexFile = "regex.xml";
	private static RegexReader regexReader = new RegexReader();
	private static HashMap<String, String> regexMap;

	public static void main(String[] args) throws Exception {
		File dir = new File(".");
		File input_file = null;
		FileTime ft = null;
		for (File f:dir.listFiles()){
			if(f.getName().matches("([a-z]*[-])*MarkedTrainingData.txt")){
				if(input_file == null){
					input_file = f;
					ft = Files.getLastModifiedTime(Paths.get(f.getName()));
				}else{
					FileTime nft =  Files.getLastModifiedTime(Paths.get(f.getName()));
					if(nft.toMillis() > ft.toMillis()){
						input_file = f;
						ft = nft;
					}
				}
			}
		}
		System.out.println("newest marked file is " + input_file.getName());
		process(input_file.getName(), null, null);
	}

	public static void process(String inputfile, String outputfile,
			String regexfile) throws Exception {
		if (inputfile == null)
			inputfile = InputFile;
		if (outputfile == null)
			outputfile = OutputFile;
		if (regexfile == null)
			regexfile = RegexFile;
		BufferedReader in = new BufferedReader(new InputStreamReader(
				new FileInputStream(inputfile), "gb2312"));

		readRegex(regexfile);
		String line = in.readLine();
		int line_num = 0;
		while (line != null) {
			++line_num;
			System.out.println(String.format("Processing line %d", line_num));
			
			byte[] byte_utf = line.getBytes("UTF-8");
			String line_utf = new String(byte_utf, 0, byte_utf.length, "UTF-8");
			for (String regex : regexMap.keySet()) {
				processLine(line_utf, line_num, regex);
			}
			line = in.readLine();
		}
		saveXml(outputfile);

	}

	private static void processLine(String line, int line_num, String regex) {
		int offset = 0;
		String[] sentences = line.split("。|！|？|：");
		for (int i = 0; i < sentences.length; ++i) {
			processSentence(sentences[i], regex, line_num, offset);
			offset += sentences.length + 1;
		}
	}

	private static void processSentence(String sentence, String regex,
			int line_num, int offset) {
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(sentence);
		while (m.find()) {
			processResult(m.group(), regex, line_num, offset + m.start());
		}
	}

	private static void processResult(String matched, String regex,
			int line_num, int offset) {
		if (regexReader.getRoot() == null || regexReader.getDocument() == null)
			return;
		NodeList regexes = regexReader.getRoot().getChildNodes();
		for (int i = 0; i < regexes.getLength(); ++i) {
			if (regexes.item(i).getNodeName().equals(RegexReader.PatternNodeName)
					&& regexes.item(i).getAttributes()
							.getNamedItem(RegexReader.PatternAttrExprName).getNodeValue()
							.equals(regex)) {
				Element match = regexReader.getDocument().createElement(RegexReader.MatchNodeName);
				match.setAttribute(RegexReader.MatchAttrTextName, matched);
				match.setAttribute(RegexReader.MatchAttrDocName, String.valueOf(line_num));
				match.setAttribute(RegexReader.MatchAttrOffsetName, String.valueOf(offset));
				regexes.item(i).appendChild(match);
				int count = 0;
				if(regexes.item(i).getAttributes().getNamedItem(RegexReader.PatternAttrCountName) != null){
					count = Integer.valueOf(regexes.item(i).getAttributes().getNamedItem(RegexReader.PatternAttrCountName).getNodeValue());
				}
				++count;
				((Element)regexes.item(i)).setAttribute(RegexReader.PatternAttrCountName, String.valueOf(count));
				return;
			}
		}
	}

	private static void readRegex(String regex_file) throws Exception {
		regexReader.readRegex(regex_file);
		NodeList children = regexReader.getRoot().getChildNodes();
		regexMap = new HashMap<String, String>();
		for (int i = 0; i < children.getLength(); ++i) {
			if (children.item(i).getNodeName().equals(RegexReader.PatternNodeName)) {
				NamedNodeMap attr = children.item(i).getAttributes();
				String regex = attr.getNamedItem(RegexReader.PatternAttrExprName)
						.getNodeValue();
				String description = attr.getNamedItem(RegexReader.PatternAttrDescName)
						.getNodeValue();
				if (regex != null && description != null)
					regexMap.put(regex, description);
			}
		}
	}

	private static void saveXml(String filename) throws FileNotFoundException,
			TransformerException {
		if (regexReader.getDocument() == null)
			return;
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		DOMSource source = new DOMSource(regexReader.getDocument());
		transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		transformer.setOutputProperty(
				"{http://xml.apache.org/xslt}indent-amount", "4");// tricky
		PrintWriter pw = new PrintWriter(new FileOutputStream(filename));
		StreamResult result = new StreamResult(pw);
		transformer.transform(source, result);
		pw.close();
	}

}
